#!/bin/bash

# Copyright Istio Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# set -x
# Creates a standard GKE cluster for testing.

set -euo pipefail

# shellcheck disable=SC2086
WD=$(dirname $0)
# shellcheck disable=SC2086
WD=$(cd $WD || exit; pwd)

# get default GKE cluster version for zone
function default_gke_version() {
  local zone=${1:?"zone is required"}
  # shellcheck disable=SC2155
  local temp_fname=$(mktemp)

  # shellcheck disable=SC2086
  gcloud container get-server-config --zone "${zone}"  > ${temp_fname} 2>&1
  # shellcheck disable=SC2181
  if [[ $? -ne 0 ]];then
    cat "${temp_fname}"
    exit 1
  fi

  # shellcheck disable=SC2002
  gke_ver=$(cat "${temp_fname}" | grep defaultClusterVersion | awk '{print $2}')
  echo "${gke_ver}"
  rm -rf "${temp_fname}"
}

# Required params
PROJECT_ID=${PROJECT_ID:?"project id is required"}

# Optional params
CLUSTER_NAME=${CLUSTER_NAME:-istio-benchmark}
ZONE=${ZONE:-us-central1-a}
# specify REGION to create a regional cluster
REGION=${REGION:-}

# Check if zone or region is valid
if [[ -n "${REGION}" ]]; then
  if [[ -z "$(gcloud compute regions list --filter="name=('${REGION:-}')" --format="csv[no-heading](name)")" ]]; then
    echo "No such region: ${REGION:-}. Exiting."
    exit 1
  fi
  ZONE="${REGION}"
else
  if [[ -z "$(gcloud compute zones list --filter="name=('${ZONE}')" --format="csv[no-heading](name)")"  ]]; then
    echo "No such zone: ${ZONE}. Exiting."
    exit 1
  fi
fi

# Specify GCP_SA to create and use a specific service account.
# Default is to use same name as the cluster - each cluster can have different
# IAM permissions. This also enables workloadIdentity, which is recommended for GCP
GCP_SA=${GCP_SA:-$CLUSTER_NAME}
GCP_CTL_SA=${GCP_CTL_SA:-${CLUSTER_NAME}-control}

# Sizing
DISK_SIZE=${DISK_SIZE:-64}
MACHINE_TYPE=${MACHINE_TYPE:-n1-standard-32}
MIN_NODES=${MIN_NODES:-"4"}
MAX_NODES=${MAX_NODES:-"70"}
IMAGE=${IMAGE:-"COS_CONTAINERD"}
MAXPODS_PER_NODE=100

# Labels and version
ISTIO_VERSION=${ISTIO_VERSION:-master}

DEFAULT_GKE_VERSION=$(default_gke_version "${ZONE}")
# shellcheck disable=SC2181
if [[ $? -ne 0 ]];then
  echo "${DEFAULT_GKE_VERSION}"
  exit 1
fi

GKE_VERSION=${GKE_VERSION-${DEFAULT_GKE_VERSION}}

# default scope for reference
# shellcheck disable=SC2034
SCOPES_DEFAULT="https://www.googleapis.com/auth/devstorage.read_only,https://www.googleapis.com/auth/logging.write,https://www.googleapis.com/auth/monitoring,https://www.googleapis.com/auth/servicecontrol,https://www.googleapis.com/auth/service.management.readonly,https://www.googleapis.com/auth/trace.append"

# Full scope is needed for the context graph API and NEG integration
SCOPES_FULL="https://www.googleapis.com/auth/cloud-platform"

SCOPES="${SCOPES_FULL}"

# A label cannot have "." in it, replace "." with "_"
# shellcheck disable=SC2001
ISTIO_VERSION=$(echo "${ISTIO_VERSION}" | sed 's/\./_/g')

function gc() {
  # shellcheck disable=SC2236
  if [[ -n "${REGION:-}" ]];then
    ZZ="--region=${REGION}"
  else
    ZZ="--zone=${ZONE}"
  fi

  SA=""
  # shellcheck disable=SC2236
  if [[ -n "${GCP_SA:-}" ]];then
    SA=("--identity-provider=${PROJECT_ID}.svc.id.goog" "--workload-pool=${PROJECT_ID}.svc.id.goog" "--service-account=${GCP_SA}@${PROJECT_ID}.iam.gserviceaccount.com" "--workload-metadata-from-node=EXPOSED")
  fi

  # shellcheck disable=SC2048
  # shellcheck disable=SC2086
  echo gcloud $* "${ZZ}" "${SA[@]}"

  # shellcheck disable=SC2236
  set +u
  if [[ -n "${DRY_RUN:-}" ]];then
    return
  fi
  set -u

  # shellcheck disable=SC2086
  # shellcheck disable=SC2048
  gcloud $* "${ZZ}" "${SA[@]}"
}

NETWORK_SUBNET="--create-subnetwork name=${CLUSTER_NAME}-subnet"
# shellcheck disable=SC2236
set +u
if [[ -n "${USE_SUBNET:-}" ]];then
  NETWORK_SUBNET="--network ${USE_SUBNET}"
fi
set -u

INSTALL_WITH_ANTHOSCLI=""
set +u
if [[ -n "${ANTHOSCLI}" ]];then
  INSTALL_WITH_ANTHOSCLI="True"
fi
set -u

ADDONS="HorizontalPodAutoscaling"
# shellcheck disable=SC2236
set +u
if [[ -n "${ISTIO_ADDON:-}" ]];then
  ADDONS+=",Istio"
fi
set -u

# set config use kpt then create cluster with anthoscli
function install_with_anthoscli {
  if [[ $(command -v anthoscli) == "" ]];then
    gcloud components install anthoscli
  fi
  if [[ $(command -v kpt) == "" ]];then
    gcloud components install kpt
  fi
  gcloud components update
  kpt cfg set gke_cluster_resources gcloud.core.project "${PROJECT_ID}"
  kpt cfg set gke_cluster_resources cluster-name "${CLUSTER_NAME}"
  kpt cfg set gke_cluster_resources gcloud.compute.zone "${ZONE}"
  kpt cfg set gke_cluster_resources max-nodes "${MAX_NODES}"
  kpt cfg set gke_cluster_resources min-nodes "${MIN_NODES}"
  kpt cfg set gke_cluster_resources max-pods-pernode "${MAXPODS_PER_NODE}"
  kpt cfg set gke_cluster_resources machine-type "${MACHINE_TYPE}"
  kpt cfg set gke_cluster_resources diskSize "${DISK_SIZE}"
  kpt cfg set gke_cluster_resources GKE_VERSION "${GKE_VERSION}"
  if [[ -n "${ISTIO_ADDON}" ]];then
     kpt cfg set gke_cluster_resources addon.istio.disabled false
  fi

  anthoscli apply -f gke_cluster_resources
}

function install_with_gcloudcontainer {
  gc beta container \
    --project "${PROJECT_ID}" \
    clusters create "${CLUSTER_NAME}" \
    --no-enable-basic-auth --cluster-version "${GKE_VERSION}" \
    --issue-client-certificate \
    --machine-type "${MACHINE_TYPE}" --image-type "${IMAGE}" --disk-type "pd-standard" --disk-size "${DISK_SIZE}" \
    --scopes "${SCOPES}" \
    --num-nodes "${MIN_NODES}" --enable-autoscaling --min-nodes "${MIN_NODES}" --max-nodes "${MAX_NODES}" --max-pods-per-node "${MAXPODS_PER_NODE}" \
    --logging=SYSTEM \
    --monitoring=SYSTEM \
    --enable-ip-alias \
    --metadata disable-legacy-endpoints=true \
    "${NETWORK_SUBNET}" \
    --default-max-pods-per-node "${MAXPODS_PER_NODE}" \
    --addons "${ADDONS}" \
    --enable-network-policy \
    --workload-metadata-from-node=EXPOSED \
    --enable-autoupgrade --enable-autorepair \
    --labels csm=1,test-date="$(date +%Y-%m-%d)",version="${ISTIO_VERSION}"
}

function cluster_create {
  # Export CLUSTER_NAME so it will be set for the create_sa.sh script, which will
  # create set up service accounts
  export CLUSTER_NAME
  mkdir -p "${WD}/tmp/${CLUSTER_NAME}"
  "${WD}/create_sa.sh" "${GCP_SA}" "${GCP_CTL_SA}"

  # shellcheck disable=SC2086
  # shellcheck disable=SC2046
  if [[ "$(gcloud beta container --project "${PROJECT_ID}" clusters list --filter=name="${CLUSTER_NAME}" --format='csv[no-heading](name)')" ]]; then
    echo "Cluster with this name already created, skipping creation and rerunning init"
  elif [[ -n "${INSTALL_WITH_ANTHOSCLI}" ]];then
    install_with_anthoscli
  else
    install_with_gcloudcontainer
  fi

  gcloud container clusters get-credentials "${CLUSTER_NAME}" --zone "${ZONE}"
}

function cluster_delete {
  gcloud beta container clusters delete --quiet "${CLUSTER_NAME}" --zone "${ZONE}"
}

if [[ $# -ne 1 ]]; then
  echo "usage: $(basename "$0") create | delete"
  exit 1
fi

case "$1" in
  create)
    cluster_create
    ;;
  delete)
    cluster_delete
    ;;
esac
